﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media;
using MTDebug;
using nl.tno.ict.multitouch.wpfmultitouch.events;
using TouchLibEvents;
using System.ComponentModel;
using System.Windows.Input;
using nl.tno.ict.multitouch.wpfmultitouch;


namespace nl.tno.ict.multitouch.wpfmultitouch.controls
{
    public class MTCanvas : Canvas, MTObject, INotifyPropertyChanged
    {
        private Ellipse _elRight;
        private bool _leftFingerdown;
        private bool _leftButtonDown;
        private long _leftFingerID;
        private bool _rightButtonDown;
        private bool _rightFingerdown;
        private long _rightFingerID;

        private long _fingerID;
        private UCDebugInfo _debuginfo;
        public event TuioMoveFingerHandler SimulatedFingerMoved;
        public event TuioRemoveFingerHandler SimulatedFingerRemoved;
        public event TuioNewFingerHandler SimulatedFingerNew;
        private int _clickCount = 0;

        private TouchManager tmc;

        public static readonly RoutedEvent ClickEvent;
        public static readonly RoutedEvent MouseDoubleClickEvent;

        private int _timeout = 1000;
        public event NotMovedEventArgs NotMoved;
        private int _fingerCount;

        public bool _showFingerPos = false;

        public double Scale { get { return tmc.scaleTrans.ScaleX; } set { } }

        public ScaleTransform ScaleTrans;
        public RotateTransform RotateTrans;
        public TranslateTransform TranslateTrans;
        
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public TouchManager TouchManager { get { return MTProcessing.GetInstance().getTouchManager(this); } }
        

        #region region propertys

        private bool _debugEnabled = false;
        /// <summary>
        /// Set the debug property. 
        /// If true, a debuginfoscreen appears in the right corner 
        /// of the screen.
        /// </summary>
        public bool DebugEnabled 
        { 
            get 
            { 
                return _debugEnabled; 
            } 
            set 
            { 
                _debugEnabled = value;                
            } 
        }
        private bool _simulationEnabled = false;
        /// <summary>
        /// Set the simulation property.
        /// If true, input (single point) with the mouse is possible.
        /// </summary>
        public bool SimulationEnabled 
        {
            get
            {
                return _simulationEnabled;
            }
            set
            {
                _simulationEnabled = value;
                if (_simulationEnabled)
                    this.simulateInput();
            }
        }

        private bool _gesturesEnabled = true;
        /// <summary>
        /// Gets or sets a value if the gestures on the MTCanvas must be recognised.
        /// </summary>
        public bool GesturesEnabled { get { return _gesturesEnabled; } set { _gesturesEnabled = value; } }

      

        #endregion





        private MTProcessing processing;



        #region MTObject Members

        public bool CanBeScaled { get { return MTProperties.GetCanBeScaled(this); } set { MTProperties.SetCanBeScaled(this, value); } }
        public bool CanBeDragged { get { return MTProperties.GetCanBeDragged(this); } set { MTProperties.SetCanBeDragged(this, value); } }
        public bool CanBeClicked { get { return MTProperties.GetCanBeClicked(this); } set { MTProperties.SetCanBeClicked(this, value); } }
        public bool CanBeRotated { get { return MTProperties.GetCanBeRotated(this); } set { MTProperties.SetCanBeRotated(this, value); } }
        /// <summary>
        /// Gets or sets a bool that describes the value of a AdornersEnabledProperty for the element.
        /// </summary>
        public bool AdornersEnabled { get { return MTProperties.GetAdornersEnabled(this); } set { MTProperties.SetAdornersEnabled(this, value); } }

        #endregion

        /// <summary>
        /// The most important of the multitouch application. MTCanvas receives the multitouch events
        /// without a multitouch canvas your application wont work
        /// </summary>
        public MTCanvas()
        {
            // Sets the TouchEnabledObjectProperty for the element always true.
            MTProperties.SetTouchEnabled(this, true); 
            _fingerID = 0;
            this.Loaded += new RoutedEventHandler(MTCanvas_Loaded);
            //this.Background = new SolidColorBrush(Colors.White);//With a transparant background the simulation has a error.. (TODO)
            this.Click += new RoutedEventHandler(MTCanvas_Click);

            
        }

        

        void MTCanvas_Click(object sender, RoutedEventArgs e)
        {
        }

        public event RoutedEventHandler MouseDoubleClick
        {
            add { AddHandler(MTButton.MouseDoubleClickEvent, value); }
            remove { RemoveHandler(MTButton.MouseDoubleClickEvent, value); }
        }

        void MTCanvas_PreviewClick(object sender, RoutedEventArgs e)
        {
        }


        static MTCanvas()
        {
           MTCanvas.ClickEvent = EventManager.RegisterRoutedEvent("ClickEvent",
           RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(MTCanvas));

           MTCanvas.MouseDoubleClickEvent = EventManager.RegisterRoutedEvent("CanvasMouseDoubleClickEvent",
           RoutingStrategy.Bubble, typeof(RoutedEvent), typeof(MTCanvas));
        }

        public event RoutedEventHandler Click
        {
            add { AddHandler(MTButton.ClickEvent, value); }
            remove { RemoveHandler(MTButton.ClickEvent, value); }
        }

        void MTCanvas_Loaded(object sender, RoutedEventArgs e)
        {
            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                processing = MTProcessing.GetInstance();
                tmc = (TouchManager)processing.getTouchManager(this);
            }
            /*if (SimulatedFingerMoved != null)
            {
                SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         position = new Point(58, 44),
                         Id = _fingerID
                     }));
            }
            _fingerID++;*/
                    
        }

        //public bool GestureModuleEnabled { get { return _gesturModuleEnabled; } set { GestureModuleEnabled = value; } }

        public bool IsDragging
        {
            get { return MTProperties.GetIsDragging(this); }
            set { MTProperties.SetIsDragging(this, value); }

        }

        public bool IsScaling
        {
            get { return MTProperties.GetIsScaling(this); }
            set { MTProperties.SetIsScaling(this, value);
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsScaling"));
            }
        }

        public bool IsRotating
        {
            get { return MTProperties.GetIsRotating(this); }
            set { MTProperties.SetIsRotating(this, value); }
        }

        /// <summary>
        /// If debug property is true, the debug info screen will always appear in the upper right corner of 
        /// the screen. 
        /// </summary>
        public void PositioningDebugInfo()
        {
            if (_debuginfo != null)
            {
                Canvas.SetTop(_debuginfo, 0);
                Canvas.SetLeft(_debuginfo, 0); //this.ActualWidth - _debuginfo.ActualWidth);
            }
        }

        /// <summary>
        /// If the simulate input property is true, the simulateInput will be used to catch the mouse events and
        /// draw a small ellipse under the mouse pointer
        /// </summary>
        private void simulateInput()
        {
             _elRight = new Ellipse();
            _elRight.Height = 10;
            _elRight.Width = 10;
            _elRight.Fill = new SolidColorBrush(Colors.Black);
            _elRight.IsHitTestVisible = false;
            Canvas.SetZIndex(_elRight, 20);

            this.PreviewMouseMove += new System.Windows.Input.MouseEventHandler(MTCanvas_PreviewMouseMove); //new System.Windows.Input.MouseEventHandler(MTCanvas_MouseMove);
            //this.MouseMove += new System.Windows.Input.MouseEventHandler(MTCanvas_MouseMove);
            this.PreviewMouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseLeftButtonDown); //+= new System.Windows.Input.MouseButtonEventHandler(MTCanvas_MouseLeftButtonDown);
            this.PreviewMouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseLeftButtonUp); //+= new System.Windows.Input.MouseButtonEventHandler(MTCanvas_MouseLeftButtonUp);
            this.PreviewMouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseRightButtonDown);
            this.PreviewMouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(MTCanvas_PreviewMouseRightButtonUp);            

            this.MouseMove += new MouseEventHandler(MTCanvas_MouseMove);
        }

        void MTCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            
        }

        internal void MTCanvas_PreviewMouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Canvas.SetZIndex(_elRight, 26);
            _rightButtonDown = false;
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {            
            _rightButtonDown = true;
            if (!_rightFingerdown)
            {
                _fingerID++;
                _rightFingerID = _fingerID;

                this.Children.Add(_elRight);
                Canvas.SetTop(_elRight, e.GetPosition(this).Y);
                Canvas.SetLeft(_elRight, e.GetPosition(this).X);
                Canvas.SetZIndex(_elRight, -10);
                _rightFingerdown = true;
                if (SimulatedFingerNew != null)
                {
                    SimulatedFingerNew(sender, new TuioNewFingerEventArgs(_fingerID));
                }

                if (SimulatedFingerMoved != null)
                {
                    SimulatedFingerMoved(sender,
                         new TuioMoveFingerEventArgs(new FingerObject()
                         {
                             CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                             Id = _fingerID
                         }));
                }
            }
            else
            {
                _rightFingerdown = false;
                if (SimulatedFingerMoved != null)
                {
                    Canvas.SetZIndex(_elRight, 1);
                    SimulatedFingerRemoved(sender, new TuioRemoveFingerEventArgs(_rightFingerID));
                }
                this.Children.Remove(_elRight);
            }
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {          
            _leftButtonDown = false;
            if (SimulatedFingerRemoved != null)
            {
                SimulatedFingerRemoved(sender, new TuioRemoveFingerEventArgs(_leftFingerID));
            }
        }

        internal void MTCanvas_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //Console.WriteLine(e.GetPosition(this).X + " " + e.GetPosition(this).Y);
            _leftButtonDown = true;
            _fingerID++;
            _leftFingerID = _fingerID;
            if (SimulatedFingerNew != null)
            {
                SimulatedFingerNew(sender, new TuioNewFingerEventArgs(_fingerID));
            }

            if (SimulatedFingerMoved != null)
            {
                SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
            }
            e.Handled = true;
        }

        internal void MTCanvas_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {            
            if (SimulationEnabled)
            {
                if (_leftButtonDown && SimulatedFingerMoved != null)
                {
                    SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
                }
                

                if (_rightButtonDown && _rightFingerdown && SimulatedFingerMoved != null)
                {
                    Canvas.SetTop(_elRight, e.GetPosition(this).Y);
                    Canvas.SetLeft(_elRight, e.GetPosition(this).X);

                    SimulatedFingerMoved(sender,
                     new TuioMoveFingerEventArgs(new FingerObject()
                     {
                         CurrentPosition = new Point(e.GetPosition(this).X, e.GetPosition(this).Y),
                         Id = _fingerID
                     }));
                }
            }
            e.Handled = true;
        }

       
        
        /// <summary>
        /// Get the left count of pixels from the desktop to window
        /// </summary>
        /// <returns>Amount of left pixels</returns>
        public double Left()
        {
            if (Parent is Window) return ((Window)Parent).Left;
            return 0.0;
        }
        
        /// <summary>
        /// Get the top count of pixels from the desktop to window
        /// </summary>
        /// <returns>Amount of left pixels</returns>
        public double Top()
        {
            if (Parent is Window) return ((Window)Parent).Top;
            return 0.0;
        }

        /// <summary>
        /// Close the nl.tno.ict.multitouch.framework.tuio listener thread
        /// </summary>
        public void Disconnect()
        {
            //_processing.Disconnect();
        }

        /// <summary>
        /// Gets or sets the timeout, in ms, used to by the NotMoved event. Default: 1000 ms
        /// </summary>s
        int MTObject.Timeout
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        #region MTObject Members
        
        public int FingerCount
        {
            get
            {
                return _fingerCount;
            }
            set
            {
                _fingerCount = value;
            }
        }
        /// <summary>
        /// Gets or sets the onTop dependency property. When true, when a finger touches the object the object
        /// gets on top of the screen (z-index changes).
        /// </summary>
        public bool OnTop
        {
            get { return MTProperties.GetOnTop(this); }
            set { MTProperties.SetOnTop(this, value); }
        }


        void MTObject.NotMoved()
        {
            if (NotMoved != null)
                NotMoved(this, new EventArgs());              
        }

        /// <summary>
        /// Set the object TouchEnabled. When an object isn't touchEnabled interaction with fingers is not
        /// possible (nothing will happen).
        /// </summary>
        public bool TouchEnabled
        {
            get { return MTProperties.GetTouchEnabled(this); }
            set { MTProperties.SetTouchEnabled(this, value); }
        }

        #endregion
    }
}
